package org.finesys.system.controller;

import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.finesys.common.core.module.R;
import org.finesys.system.constants.ControllerRestApiConfig;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.hutool.core.util.NumberUtil;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping(ControllerRestApiConfig.SYSTEM)
@RequiredArgsConstructor
@Tag(description = "system", name = "系统监控")
@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
public class SysSystemInfoController {

    private final RedisTemplate<String, String> redisTemplate;

    /**
     * 获取系统JVM监控信息
     *
     * @return 包含系统JVM监控信息的响应对象
     */
    @GetMapping("/info")
    public R<?> info() {
        Runtime runtime = Runtime.getRuntime();
        Map<String, Object> info = new HashMap<>(16);
        info.put("osName", runtime.availableProcessors());
        info.put("osArch", System.getProperty("os.arch"));
        info.put("osVersion", System.getProperty("os.version"));
        info.put("cpuCore", runtime.availableProcessors());
        info.put("homeDir", System.getProperty("user.home"));
        info.put("javaHome", System.getProperty("java.home"));
        info.put("javaVersion", System.getProperty("java.version"));
        info.put("memory.runtime.total", runtime.totalMemory());
        info.put("memory.runtime.free", runtime.freeMemory());
        info.put("memory.runtime.max", runtime.maxMemory());
        info.put("memory.runtime.used", runtime.totalMemory() - runtime.freeMemory());
        info.put("memory.runtime.usage", NumberUtil.div(runtime.totalMemory() - runtime.freeMemory(), runtime.totalMemory()));
        //物理内存
        OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
        if (operatingSystemMXBean instanceof com.sun.management.OperatingSystemMXBean) {
            com.sun.management.OperatingSystemMXBean sunOperatingSystemMXBean = (com.sun.management.OperatingSystemMXBean) operatingSystemMXBean;
            //物理内存
            info.put("physical.total", sunOperatingSystemMXBean.getTotalPhysicalMemorySize());
            //空闲物理内存
            info.put("physical.free", sunOperatingSystemMXBean.getFreePhysicalMemorySize());
            //已使用物理内存
            info.put("physical.used", sunOperatingSystemMXBean.getTotalPhysicalMemorySize() - sunOperatingSystemMXBean.getFreePhysicalMemorySize());
            //物理内存使用率
            info.put("physical.usage", NumberUtil.div(sunOperatingSystemMXBean.getTotalPhysicalMemorySize() - sunOperatingSystemMXBean.getFreePhysicalMemorySize(), sunOperatingSystemMXBean.getTotalPhysicalMemorySize()));
            //虚拟内存
            info.put("totalSwapSpaceSize", sunOperatingSystemMXBean.getTotalSwapSpaceSize());
            //空闲虚拟内存
            info.put("freeSwapSpaceSize", sunOperatingSystemMXBean.getFreeSwapSpaceSize());
        }
        return R.success(info);
    }

    /**
     * 缓存监控
     *
     * @return R<Object>
     */
    @GetMapping("/cache")
    public R<?> cache() {
        Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::info);
        Properties commandStats = (Properties) redisTemplate
                .execute((RedisCallback<Object>) connection -> connection.serverCommands().info("commandstats"));
        Object dbSize = redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::dbSize);

        if (commandStats == null) {
            return R.failed("获取异常");
        }

        Map<String, Object> result = new HashMap<>(3);
        result.put("info", info);
        result.put("dbSize", dbSize);

        List<Map<String, String>> pieList = new ArrayList<>();
        commandStats.stringPropertyNames().forEach(key -> {
            Map<String, String> data = new HashMap<>(2);
            String property = commandStats.getProperty(key);
            data.put("name", StringUtils.removeStart(key, "cmdstat_"));
            data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
            pieList.add(data);
        });

        result.put("commandStats", pieList);
        return R.success(result);
    }

}
